package com.hundsun.cprs.yyt.service.trade.service.impl;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;

import com.hundsun.cprs.yyt.service.order.enums.EnumOrderSNCode;
import com.hundsun.cprs.yyt.service.trade.domain.*;
import com.hundsun.cprs.yyt.service.trade.service.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionTemplate;

import com.hundsun.cprs.yyt.common.base.BaseService;
import com.hundsun.cprs.yyt.common.exception.ServiceException;
import com.hundsun.cprs.yyt.service.common.dto.FundBatchRequest;
import com.hundsun.cprs.yyt.service.common.enums.EnumFundBidCode;
import com.hundsun.cprs.yyt.service.common.service.RemoteTradeFundService;
import com.hundsun.cprs.yyt.service.rabbit.RoutingKeyConstants;
import com.hundsun.cprs.yyt.service.trade.dao.TradeMatchDao;
import com.hundsun.cprs.yyt.service.trade.dao.TradeMatchDetailDao;
import com.hundsun.cprs.yyt.service.trade.enums.EnumEntustBSType;
import com.hundsun.cprs.yyt.service.trade.enums.EnumTradeEntrustStatus;
import com.hundsun.cprs.yyt.service.trade.enums.EnumTradeStatus;
import com.hundsun.cprs.yyt.util.ShortUUIDGenerator;

/**
 * @author Administrator
 * @date 2019年4月18日
 */
@Service
public class TradeMatchServiceImpl extends BaseService implements TradeMatchService {
    @Autowired
    private TradeMatchDao tradeMatchDao;
    @Autowired
    private TradeMatchDetailDao tradeMatchDetailDao;
    @Autowired
    private TradeEntrustService tradeEntrustService;
    @Autowired
    private TradeMatchDetailService tradeMatchDetailService;
    @Autowired
    private TradeEntrustRollbackService rollbackService;
    @Autowired
    private RemoteTradeFundService remoteTradeFundService;
    @Autowired
    private RabbitTemplate template;
    @Autowired
    private Executor asyncFundExecutor;
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private TradeCancelFlowService cancelFlowService;
    
    @Override
    public void updateAfterMatch(TradeMatch tradeMatch) {
        Map<Long, TradeEntrust> waitUpdateEntrust = new LinkedHashMap<Long, TradeEntrust>();
        for(TradeMatchDetail detail : tradeMatch.getDetails()){
            //处理匹配明细
            detail.setSn(ShortUUIDGenerator.generate());
            if (EnumEntustBSType.SELL.getCode().toString().equals(detail.getEntrust().getEntrustBs())) {
                detail.setIsFundProcess(TradeMatchDetail.FUND_PROCESS.WAIT.ordinal());
            } else {
                detail.setIsFundProcess(TradeMatchDetail.FUND_PROCESS.DONT.ordinal());
            }
            //取同一笔委托单最后一次匹配更新
            waitUpdateEntrust.put(detail.getEntrust().getId(), detail.getEntrust());
            //子状态变更，这里做下大类状态的同步变动
            if (EnumTradeEntrustStatus.DEALT.getStatus() == detail.getEntrust().getEntrustStatus()) {
                detail.getEntrust().setStatus(EnumTradeStatus.DEALT.getStatus());
            } else {
                detail.getEntrust().setStatus(EnumTradeStatus.COMMITED.getStatus());
            }
        }
        List<TradeEntrust> entrusts = new ArrayList<TradeEntrust>(waitUpdateEntrust.values());
        // 优先处理落库，独立事务控制
        handleTradeMatch(tradeMatch,entrusts);
        // 卖家资金处理
        handleFundAfterMatch(tradeMatch.getDetails());
        // 委托单状态变更通知
        notifyEntrustStatusChange(entrusts);
        //通知发送匹配成功短信（只有部成才发）
        notifyMatchCompleteToSendSms(tradeMatch.getDetails());
    }
    
    protected void handleTradeMatch(TradeMatch tradeMatch,List<TradeEntrust> entrusts){
        DefaultTransactionDefinition defintion = new DefaultTransactionDefinition();
        defintion.setPropagationBehavior(Propagation.REQUIRES_NEW.value());
        defintion.setIsolationLevel(Isolation.READ_COMMITTED.value());
        TransactionStatus status = transactionTemplate.getTransactionManager().getTransaction(defintion);
        try{
            // 委托订单状态落库
            tradeEntrustService.batchUpdateEntrust(entrusts);
            // 匹配表落库
            tradeMatchDao.insert(tradeMatch);
            // 匹配详情落库
            tradeMatchDetailDao.batchInsert(tradeMatch.getDetails());
            
            transactionTemplate.getTransactionManager().commit(status);
        } catch(Exception e) {
            transactionTemplate.getTransactionManager().rollback(status);
            throw e;
        }
    }
    
    protected void handleFundAfterMatch(final List<TradeMatchDetail> details){
        if (details == null) {
            return;
        }
        if (asyncFundExecutor != null) {
            //异步处理
            asyncFundExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    for(TradeMatchDetail detail : details){
                        if (EnumEntustBSType.SELL.getCode().toString().equals(detail.getEntrust().getEntrustBs())) {
                            FundBatchRequest request = FundBatchRequest.builder("system", detail.getSn(), "挂售交易收入,扣除手续费及综合管理费.");
                            request.addTask(detail.getEntrust().getFundAccount(), EnumFundBidCode.CFUND_170101, null, detail.getMatchFundAmount())
                                   .addTask(detail.getEntrust().getFundAccount(), EnumFundBidCode.CFUND_170701, null, detail.getMatchCommission())
                                   .addTask(detail.getEntrust().getFundAccount(), EnumFundBidCode.CFUND_170702, null, detail.getMatchManagement());
                            try {
                                remoteTradeFundService.batchExecute(request);
                                tradeMatchDetailService.updateTradeMatchDetail(detail.getSn(), TradeMatchDetail.FUND_PROCESS.SUCCESS.ordinal());
                            } catch (ServiceException e) {
                                 logger.error("匹配成功异步处理资金异常:",e);
                                tradeMatchDetailService.updateTradeMatchDetail(detail.getSn(), TradeMatchDetail.FUND_PROCESS.FAIL.ordinal());
                            }
                        }
                    }
                }
            });
        }
    }
    
    /**
     * 通知委托订单匹配结束
     * @param entrusts
     */
    protected void notifyEntrustStatusChange(List<TradeEntrust> entrusts){
        if (entrusts != null) {
            for(TradeEntrust entrust : entrusts){
                if (EnumTradeEntrustStatus.CANCELED.getStatus() == entrust.getEntrustStatus()) {
                    //已撤
                    template.convertAndSend(RoutingKeyConstants.YYT_ENTRUST_STATUS_CANCELED,entrust);
                } else if(EnumTradeEntrustStatus.PART_CANCELED.getStatus() == entrust.getEntrustStatus()) {
                    //部撤
                    template.convertAndSend(RoutingKeyConstants.YYT_ENTRUST_STATUS_PART_CANCELED,entrust);
                } else if(EnumTradeEntrustStatus.DEALT.getStatus() == entrust.getEntrustStatus()){
                    //已成
                    template.convertAndSend(RoutingKeyConstants.YYT_ENTRUST_STATUS_DEALT,entrust);
                }else {
                    //不发
                }
            }
        }
    }

    /**
     * 匹配成功发送部成短信
     * @param tradeMatchDetails
     *
     */
    protected void notifyMatchCompleteToSendSms(List<TradeMatchDetail> tradeMatchDetails){
        for(TradeMatchDetail detail : tradeMatchDetails) {
            if (EnumEntustBSType.SELL.getCode().toString().equals(detail.getEntrust().getEntrustBs()) &&
                    EnumTradeEntrustStatus.PART_DEALT.getStatus() == detail.getEntrust().getEntrustStatus()) {
                //部成
                template.convertAndSend(RoutingKeyConstants.YYT_ENTRUST_STATUS_PART_DEALT, detail);
            }
        }
    }

    @Override
    public List<TradeMatchDetail> selectCounterpartyTradeMatchDetailList(Long entrustId,String entrustBs) {
        return tradeMatchDetailDao.selectCounterpartyTradeMatchDetailList(entrustId,entrustBs);
    }

    @Override
    public List<TradeMatchDetail> selectCounterpartyTradeMatchDetailListforView(Long entrustId, String entrustBs) {
        return tradeMatchDetailDao.selectCounterpartyTradeMatchDetailListforView(entrustId,entrustBs);
    }

    @Override
    @Transactional
    public void cancelEntrust(List<TradeEntrust> tradeEntrustList) {
        if (tradeEntrustList == null || tradeEntrustList.isEmpty()) {
            return;
        }
        // 同步变更下大类状态 
        for(TradeEntrust entrust : tradeEntrustList){
            if (EnumTradeEntrustStatus.CANCELED.getStatus() == entrust.getEntrustStatus() ||
                EnumTradeEntrustStatus.PART_CANCELED.getStatus() == entrust.getEntrustStatus()) {
                entrust.setStatus(EnumTradeStatus.CANCELED.getStatus());
            }
        }
        // 委托订单状态落库
        tradeEntrustService.batchUpdateEntrust(tradeEntrustList);
        
        notifyEntrustStatusChange(tradeEntrustList);
    }

    @Override
    public void rollbackEntrust(TradeRollbackFlow tradeRollbackFlow, TradeEntrust tradeEntrust) {
        DefaultTransactionDefinition defintion = new DefaultTransactionDefinition();
        defintion.setPropagationBehavior(Propagation.REQUIRES_NEW.value());
        defintion.setIsolationLevel(Isolation.READ_COMMITTED.value());
        TransactionStatus status = transactionTemplate.getTransactionManager().getTransaction(defintion);
        try{
            rollbackService.updateRollbackFlow(tradeRollbackFlow);
            Integer expectEntrustStatus = tradeEntrust.getEntrustStatus();
            tradeEntrust.setStatus(EnumTradeStatus.INIT.getStatus());
            tradeEntrust.setEntrustStatus(EnumTradeEntrustStatus.INIT.getStatus());
            tradeEntrustService.updateEntrustStatus(tradeEntrust, expectEntrustStatus);
            
            transactionTemplate.getTransactionManager().commit(status);
        } catch(Exception e) {
            transactionTemplate.getTransactionManager().rollback(status);
            throw e;
        }
        
        //撤回成功通知
        template.convertAndSend(RoutingKeyConstants.YYT_TRADE_ENTRUST_ROLLBACK_SUCCESS,tradeEntrust);
    }

    @Override
    public void updateRollbackFlowStatus(TradeRollbackFlow tradeRollbackFlow) {
        rollbackService.updateRollbackFlow(tradeRollbackFlow);
    }

    @Override
    public void updateCancelFlowAfterSuccess(TradeCancelFlow cancelFlow, TradeEntrust tradeEntrust) {
        DefaultTransactionDefinition defintion = new DefaultTransactionDefinition();
        defintion.setPropagationBehavior(Propagation.REQUIRES_NEW.value());
        defintion.setIsolationLevel(Isolation.READ_COMMITTED.value());
        TransactionStatus status = transactionTemplate.getTransactionManager().getTransaction(defintion);
        try{
            updateCancelFlowStatus(cancelFlow);
            Integer expectEntrustStatus = tradeEntrust.getEntrustStatus();
            if(tradeEntrust.getEntrustAmount() > tradeEntrust.getSurplusEntrustAmount()){
                //部撤
                tradeEntrust.setStatus(EnumTradeStatus.CANCELED.getStatus());
                tradeEntrust.setEntrustStatus(EnumTradeEntrustStatus.PART_CANCELED.getStatus());
            } else {
                //全部撤单
                tradeEntrust.setStatus(EnumTradeStatus.CANCELED.getStatus());
                tradeEntrust.setEntrustStatus(EnumTradeEntrustStatus.CANCELED.getStatus());
            }
            tradeEntrustService.updateEntrustStatus(tradeEntrust, expectEntrustStatus);

            transactionTemplate.getTransactionManager().commit(status);
        } catch(Exception e) {
            transactionTemplate.getTransactionManager().rollback(status);
            throw e;
        }

        //委托单撤单通知
        if (EnumTradeEntrustStatus.CANCELED.getStatus() == tradeEntrust.getEntrustStatus()) {
            template.convertAndSend(RoutingKeyConstants.YYT_ENTRUST_STATUS_CANCELED,tradeEntrust);
        } else if(EnumTradeEntrustStatus.PART_CANCELED.getStatus() == tradeEntrust.getEntrustStatus()) {
            template.convertAndSend(RoutingKeyConstants.YYT_ENTRUST_STATUS_PART_CANCELED,tradeEntrust);
        }
    }

    @Override
    public void updateCancelFlowStatus(TradeCancelFlow cancelFlow) {
        cancelFlowService.updateCancelFlow(cancelFlow);
    }
}
